#include "Server.h"

// 判断文件描述符集合的最大值
#define FDS_MAX(FD_1, FD_2) FD_1 > FD_2 ? FD_1 : FD_2

// 设定最大连接客户端数量
#define LIN_MAX 3

int main(int argc, char const *argv[])
{
	/************** 测试参数合法性 **************/
	if (argc != 2)
	{
		printf("输入的格式错误 %s port\n", argv[0]);
		exit(1);
	}

	/************** 声明变量 **************/
	int sock_client; // 客户端 套接字
	int sock_server; // 服务端 套接字

	int sock_client_arr[LIN_MAX] = {0}; // 客户端 套接字 数组
	int sock_client_len = 0;			// 用于管理 客户端套接字长度

	char buf_recv[1024];								// 接收字符串
	char buf_send[1024] = "恭喜你,通讯成功,我已收到\n"; // 发送字符串
	char buf_recv_len = 0;								// 记录接收字符串长度 用于判定是否断开连接

	int fds_num = 0; // 多路IO 就绪文件描述符个数

	/************** 初始化TCP **************/
	// atoi(argv[1])    端口号
	// sock_server      服务器套接字
	sock_server = tcp_server_init(atoi(argv[1]));

	/************** 监听 **************/
	if (-1 == listen(sock_server, LIN_MAX))
	{
		ERRLOG("监听失败");
		close(sock_server);
		return -3;
	}

	/************** 多路IO **************/
	// 声明集合
	fd_set Tcp_client_fds;		// 母本
	fd_set Tcp_client_fds_temp; // 副本

	// 声明集合的的最大值
	unsigned int Tcp_fds_max = 0;

	// 清空母本集合
	FD_ZERO(&Tcp_client_fds);

	// 将服务器套接字 加入到 集合中
	FD_SET(sock_server, &Tcp_client_fds);
	// 更新最大值
	Tcp_fds_max = FDS_MAX(sock_server, Tcp_fds_max);

	while (1)
	{
		// 清空副本
		FD_ZERO(&Tcp_client_fds_temp);

		// 母本赋值给副本
		Tcp_client_fds_temp = Tcp_client_fds;

		// 多路IO复用
		// fds_num  存储返回值
		// fds_num == -1 代表错误
		// fds_num > 0 代表读取到的就绪套接字个数
		// fds_num = 0 超时
		fds_num = select(Tcp_fds_max + 1, &Tcp_client_fds_temp, NULL, NULL, NULL);
		if (fds_num == -1)
		{
			printf("select 错误\n");
			continue;
		}

		/************** 新用户连接 **************/
		// 检查 sock_server 是否在 Tcp_client_fds_temp 集合中，如果在，则表示有客户端的连接请求等待处理。
		if (FD_ISSET(sock_server, &Tcp_client_fds_temp))
		{
			// 等待客户端连接
			// 调用 accept 函数接受客户端的连接，accept 函数会返回一个新的套接字 sock_client 用于与该客户端通信。
			sock_client = accept(sock_server, NULL, NULL);
			if (sock_client == -1)
			{
				ERRLOG("连接失败");
				return 0;
			}

			// 判断是否超过最大连接数

			if (sock_client_len >= LIN_MAX + 1)
			{
				send(sock_client, "超过客户端最大连接数量", strlen("超过客户端最大连接数量"), 0);
				close(sock_client);
				printf("超过客户端最大连接数量\n");
				continue;
			}

			// 连接后 写入到数组中
			// 将新的客户端套接字添加到 sock_client_arr 数组中，并将其长度加 1。
			sock_client_arr[sock_client_len++] = sock_client;

			printf("连接成功 套接字:%d max = %d\n", sock_client, Tcp_fds_max);

			// 将客户端套接字 加入到 集合中
			FD_SET(sock_client, &Tcp_client_fds);
			// 获取最大值
			Tcp_fds_max = FDS_MAX(sock_client, Tcp_fds_max);
		}

		/************** 客户端信息 **************/
		// 主要处理客户端的数据接收和发送操作。
		else
		{
			// 遍历集合
			for (size_t i = 0; i < sock_client_len && fds_num != 0; i++)
			{
				// 判断 那个 客户端套接字 就绪
				if (FD_ISSET(sock_client_arr[i], &Tcp_client_fds_temp))
				{
					// 对套接字就绪个数做减一操作  优化 扫描次数
					fds_num--;
					// 清空接收套接字
					memset(buf_recv, 0, sizeof(buf_recv));
					// 接收信息
					buf_recv_len = recv(sock_client_arr[i], buf_recv, sizeof(buf_recv), 0);
					if (buf_recv_len == 0) // 客户端退出
					{
						// 从集合中删除
						FD_CLR(sock_client_arr[i], &Tcp_client_fds);
						// 如果删除的是最大的套接字 则需要将 Tcp_fds_max 减一
						if (sock_client_arr[i] == Tcp_fds_max)
						{
							Tcp_fds_max--;
						}
						// 关闭套接字
						close(sock_client_arr[i]);
						continue;
					}
					// 打印接收到的数据
					printf("接收信息:%s\n", buf_recv);
					// 向客户端发送一个信息
					send(sock_client_arr[i], buf_send, strlen(buf_send), 0);
				}
			}
		}
	}

	return 0;
}
